package com.example.netcamerastreamdemo;

import android.content.Context;
import android.media.MediaDataSource;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Build;
import android.util.Log;
import android.view.SurfaceView;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;

import com.google.gson.Gson;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Hashtable;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;

@RequiresApi(api = Build.VERSION_CODES.M)
public class SocketMediaDataSource extends MediaDataSource {
    private static final String TAG = "StreamMediaDataSource";
//    private static final String STREAM_START_FLAG = "VSDK_CMD_TX_RT_VIDEO_START";
        private static final String STREAM_START_FLAG = "PLAY_FLV";
    private static final String STREAM_STOP_FLAG = "VSDK_CMD_TX_RT_VIDEO_STOP";
    private static final String STREAM_HEART_BEAT_FLAG = "HB";

    private static final String SOCKET_ADDRESS = "socketlv";
    private static final int TIMEOUT_VALUE = 30;
    private WebSocket mWebSocket;
    private Gson mGson = new Gson();
    private Hashtable<Integer, byte[]> mStreamData = new Hashtable<>();
    private int mWriteIndex = -1;
    private SurfaceView mSurfaceView;
    private String mWebsocketUrl;
    private VideoStreamPlayer.MsgData mAuthData;
    private boolean isPlaying = false;
    private boolean isWebsocketConnected = false;
    private int mReadIndex = 0;
    private StreamCallback mStreamCallback;
    private int mUnfinishFrameCount = 0;
    private int mDataLength = 0;
    Context mContext;
    Socket mSocket;
    LocalServerSocket mLSS;
    LocalSocket mLSrecv;
    LocalSocket mLSsend;
    BufferedInputStream bufferedInputStream;

    public SocketMediaDataSource(
            Context context,
            @NonNull SurfaceView mSurfaceView,
            @NonNull String url,
            @NonNull VideoStreamPlayer.MsgData authData) {
        this.mContext = context;
        this.mSurfaceView = mSurfaceView;
        this.mWebsocketUrl = url;
        this.mAuthData = authData;

    }

    public void setmStreamCallback(StreamCallback streamCallback) {
        this.mStreamCallback = streamCallback;
    }

    @Override
    public int readAt(long position, byte[] bytes, int offset, int size) throws IOException {
        mLSrecv = mLSS.accept();
        InputStream inputStream = mLSrecv.getInputStream();
        bufferedInputStream = new BufferedInputStream(inputStream);
        int c = bufferedInputStream.read(bytes, offset, size);
        Log.i(TAG, "---readAt===" + c);
        return c;
    }

    @Override
    public long getSize() throws IOException {
        Log.i(TAG, "---getSize===" + mDataLength);
        return 0;
    }

    @Override
    public void close() throws IOException {
        Log.i(TAG, "---close===");

    }

    public boolean prepare(){
        if (mSurfaceView == null){
            return false;
        }
        if (mWebsocketUrl.isEmpty()){
            return false;
        }
        if (mAuthData == null){
            return false;
        }
        Log.i(TAG, "---一级准备===");
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    mLSS = new LocalServerSocket(SOCKET_ADDRESS);
//                    while (true){
//                        InputStream inputStream = mLSrecv.getInputStream();
//                        byte[] bytes = new byte[1024];
//                        int len = -1;
//                        while ((len = inputStream.read(bytes)) != -1){
//                            Log.i(TAG, "---收到的数据===" + len);
//                        }
//                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    mLSsend = new LocalSocket();
                    mLSsend.connect(new LocalSocketAddress(SOCKET_ADDRESS));
                    mLSrecv = mLSS.accept();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        initWebSocket();


        return true;
    }

    public void startPlay(){
        if (isPlaying){
            return;
        }
        isPlaying = true;
        sendStartMsg();
    }

    public void stopPlay(){
        if (!isPlaying){
            return;
        }
        reset();
        sendStopVideoMsg();
    }

    public void release(){
        mWebSocket.cancel();
    }

    private void reset(){
        try {
            mLSsend.close();
            mLSrecv.close();
            mLSS.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        isPlaying = false;
        mStreamData.clear();
        mWriteIndex = -1;
    }

    private void sendStartMsg() {
        if (isWebsocketConnected) {
            VideoStreamPlayer.MsgData startVideoMsg = new VideoStreamPlayer.MsgData(
                    STREAM_START_FLAG,
                    mAuthData.dev_guid,
                    mAuthData.video_chnn,
                    mAuthData.sub_chnn,
                    mAuthData.rec_path);
            mWebSocket.send(mGson.toJson(startVideoMsg));
        }
    }

    private void sendStopVideoMsg(){
        if (isWebsocketConnected) {
            VideoStreamPlayer.MsgData stopVideoMsg = new VideoStreamPlayer.MsgData(
                    STREAM_STOP_FLAG,
                    mAuthData.dev_guid,
                    mAuthData.video_chnn,
                    mAuthData.sub_chnn);
            mWebSocket.send(mGson.toJson(stopVideoMsg));
        }
    }

    private void sendHeartBeatMsg(){
        if (isWebsocketConnected) {
            VideoStreamPlayer.MsgData heartBeatMsg = new VideoStreamPlayer.MsgData();
            heartBeatMsg.cmd = STREAM_HEART_BEAT_FLAG;
            mWebSocket.send(mGson.toJson(heartBeatMsg));
        }
    }

    private void initWebSocket(){
        OkHttpClient mClient = new OkHttpClient.Builder()
                .readTimeout(TIMEOUT_VALUE, TimeUnit.SECONDS)//设置读取超时时间
                .writeTimeout(TIMEOUT_VALUE, TimeUnit.SECONDS)//设置写的超时时间
                .connectTimeout(TIMEOUT_VALUE, TimeUnit.SECONDS)//设置连接超时时间
                .build();

        Request request = new Request.Builder().get().url(mWebsocketUrl).build();
        mWebSocket = mClient.newWebSocket(request, new WebSocketListener() {
            @Override
            public void onOpen(WebSocket webSocket, Response response) {
                super.onOpen(webSocket, response);
                Log.i(TAG, "---onOpen===");
                isWebsocketConnected = true;
            }

            @Override
            public void onMessage(WebSocket webSocket, String text) {
                super.onMessage(webSocket, text);
                Log.i(TAG, "---onMessage===" + text);
                if (text.contains(STREAM_START_FLAG)){
//                    mStreamStartTime = System.currentTimeMillis();
                }
            }

            @Override
            public void onMessage(WebSocket webSocket, ByteString bytes) {
                super.onMessage(webSocket, bytes);
                Log.i(TAG, "---onMessage===" + (bytes.size() - 44));
                mWriteIndex++;
//                mStreamData.put(mWriteIndex, bytes.substring(44).toByteArray());
                mStreamData.put(mWriteIndex, bytes.toByteArray());
                if (mWriteIndex == 1){
                    mStreamCallback.streamIsStart();
                }
                try {
                    mLSsend.getOutputStream().write(bytes.toByteArray());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onClosing(WebSocket webSocket, int code, String reason) {
                super.onClosing(webSocket, code, reason);
                Log.i(TAG, "---onClosing===" + reason);
                isWebsocketConnected = false;
            }

            @Override
            public void onClosed(WebSocket webSocket, int code, String reason) {
                super.onClosed(webSocket, code, reason);
                Log.i(TAG, "---onClosed===" + reason);
                isWebsocketConnected = false;
            }

            @Override
            public void onFailure(WebSocket webSocket, Throwable t, Response response) {
                super.onFailure(webSocket, t, response);
                Log.i(TAG, "---onFailure===" + t.toString());
                isWebsocketConnected = false;
                initWebSocket();
            }
        });
    }

    interface StreamCallback{
        void streamIsStart();
    }
}
